﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using MassSpectrum.dto;

using lpcieapi;
using l502api;

namespace MassSpectrum.Model
{
    public class DataReader : IDataReader
    {
        const uint RECV_BUF_SIZE = 8 * 1024 * 1024;
        const uint RECV_TOUT = 5;
        const uint ARRSIZE = 50;
       

        L502 device;

        public static UInt32[] rcv_buf = new UInt32[RECV_BUF_SIZE]; /* буфер для приема сырых данных */
        
        public static double[] adcData = new double[RECV_BUF_SIZE]; /* буфер для данных АЦП */
        
        public static UInt32[] dinData = new UInt32[RECV_BUF_SIZE]; /* буфер для отсчетов цифровых входов */
       
        public static UInt32 adcSize, dinSize; /* размер действительных данных в adcData и dinData */
        public static UInt32 firstLch; // номер логического канала,  которому соответств

        private static IList<double> Mass = new List<double>();
      
        

        public bool GetConnection()
        {
            if (device == null)
            {
                lpcie.Errs result;
                String[] serials;
                
                Int32 res = L502.GetSerialList(out serials, 0);
                if (res > 0)
                {
                    device = new L502();
                    result = device.Open(serials[0]);
                    lpcie.Errs err = lpcie.Errs.OK;
                    
                    device.LChannelCount = 2;

                    /* Настраниваем таблицу логических каналов */
                    err = device.SetLChannel(0, 0, L502.LchMode.COMM, L502.AdcRange.RANGE_02, 64);

                   
                    if (err == lpcie.Errs.OK)
                    {
                        err = device.SetLChannel(1, 1, L502.LchMode.COMM, L502.AdcRange.RANGE_05, 96);
                    }
/*
                    if (err == lpcie.Errs.OK)
                    {
                        err = device.SetLChannel(2, 2, L502.LchMode.DIFF, L502.AdcRange.RANGE_1, 128);
                    }

                    if (err == lpcie.Errs.OK)
                    {
                        err = device.SetLChannel(3, 3, L502.LchMode.DIFF, L502.AdcRange.RANGE_1, 128);
                    }
               */     
                    device.SyncMode = L502.Sync.INTERNAL;
                    device.SyncStartMode = L502.Sync.INTERNAL;

                    double f_acq = 100000;
                    double f_lch = f_acq/device.LChannelCount;
                  

                    err = device.SetAdcFreq(ref f_acq, ref f_lch);
              
                                   
                    device.Configure(0);
                }
                else
                {
                   return false;
                }

                
                  result = device.StreamsEnable(L502.Streams.ADC);
                  result = device.StreamsDisable(L502.Streams.DIN);
                
                // включаем потоки ввода-вывода
                result = device.StreamsStart();
            }

            return true;

        }
/*
        public  void WriteDump()
        {
            if (System.IO.File.Exists("dump.txt"))
            {
                using (StreamWriter sw = new StreamWriter(File.Open("dump.txt", FileMode.Append)))
                {
                    for (int i = 0; i <= 1000; i++)
                    {
                        sw.WriteLine("rcv_buf[" + i.ToString() + "] = " + rcv_buf[i].ToString("X") + "adcData[" + i.ToString() + "] = " + adcData[i].ToString());
                    }
                }

            }
            else
            {
                using (StreamWriter sw = new StreamWriter(File.Open("dump.txt", FileMode.Create)))
                {
                    for (int i = 0; i <= 1000; i++)
                    {
                        sw.WriteLine("rcv_buf[" + i.ToString() + "] = " + rcv_buf[i].ToString("X") + "adcData[" + i.ToString() + "] = " + adcData[i].ToString());
                    }
                }
            }

        }
        */
        public Data ReadData()
        {
            Data data = new Data();
            lpcie.Errs err;
          
            
            /* принимаем данные синхронного ввода */
                    Int32 rcv_size = device.Recv(rcv_buf, RECV_BUF_SIZE, RECV_TOUT);
                    /* значение меньше нуля означает ошибку... */
                    if (rcv_size < 0)
                        err = (lpcie.Errs)rcv_size;
                    else if (rcv_size > 0)
                    {
                        /* если больше нуля - значит приняли новые данные */
                        dinSize = RECV_BUF_SIZE;
                        adcSize = RECV_BUF_SIZE;
                        /* получаем номер лог. какнала, соответствующий первому
                            отсчету АЦП, так как до этого могли обработать
                            некратное количество кадров */
                        firstLch = device.NextExpectedLchNum;

                        /* разбираем данные на синхронный ввод и отсчеты АЦП и
                            переводим АЦП в Вольты */
                        err = device.ProcessData(rcv_buf, (uint) rcv_size, L502.ProcFlags.VOLT,
                            adcData, ref adcSize, dinData, ref dinSize);
                        
                    }

                    double[] mydata = new double[4];

                    UInt32 lch_cnt = device.LChannelCount;

                    /* устанавливаем в индикаторах значение первого отсчета из массива */
                    for (uint i = 0; (i < lch_cnt) && (i < adcSize); i++)
                    { mydata[(firstLch + i) % lch_cnt] = adcData[i]; }

                    data.Intensity = -1* mydata[0];

                    data.Mass = MassConverter(mydata[1]); 
                        
                  data.Temperature = TempCalibr(mydata[3]); // внимание : при припайке ячейка -4й канал, печка 3-й

                   // data.Temperature = mydata[3];
                    data.Heating = HeatCalibr(mydata[2]) ;

            return data;
        }

        public void StartReading()
        {
            lpcie.Errs err = device.StreamsStart();
        }

        private double MassConverter(double x)
        {
            x *= 1000;
            return 22.83978 - 0.7519 * x + 0.01398 * x*x - 7.12802E-5 * Math.Pow(x,3) + 2.46248E-7 * Math.Pow(x,4) - 4.18395E-10 * Math.Pow(x,5) + 2.96567E-13 * Math.Pow(x,6);
        }

        private double TempCalibr(double x)
        {
           // return x * 18.82979 - 0.16555;
       //   return 18.94191*x -0.08801;
            return 18.916 * x - 0.119815;
            
        }

        private double HeatCalibr(double x)
        {
            return 18.56123 * x - 0.16422;
        }

        public IList<Data> ReadData(string path)
        {
            string Line;
            string[] strArr;
            char[] charArr = new char[] { ';', '\t' }; // используемый в файле разделитель
            IList<Data> Data = new List<Data>();
            try
            {
                if (File.Exists(path))
                {
                    FileStream fs = File.OpenRead(path);
                    StreamReader sr = new StreamReader(fs, Encoding.Default);
                    while (sr.EndOfStream != true)
                    {
                        Line = sr.ReadLine();
                        strArr = Line.Split(charArr);

                        Data data = new Data();
                        try
                        {
                            data.id = (strArr[0] != "") ? Convert.ToUInt64(strArr[0]) : 0;

                            data.Time = (strArr[1] != "") ? Convert.ToDateTime(strArr[1]) : DateTime.Now;

                            data.Intensity = (strArr[3] != "") ? Convert.ToDouble(strArr[3]) : 0;

                            data.Mass = (strArr[2] != "") ? Convert.ToDouble(strArr[2]) : 0;
                            
                            data.Temperature = (strArr[4] != "") ? Convert.ToDouble(strArr[4]) : 0;
                            
                            data.Heating = (strArr[5] != "") ? Convert.ToDouble(strArr[5]) : 0;
                        }
                        catch 
                        { return null; }

                        Data.Add(data);

                    }
                    sr.Close();
                }
            }
            catch 
            {
                return null;
            }
            return Data;
        }

        public void CloseConnection()
        {
            device.StreamsStop();
            device.Close();
        }

    }
}
